#include <map>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

#include "../Mutex.h"

using std::string;

class CustomerData : boost::noncopyable
{
 public:
  CustomerData()
    : data_(new Map)
  { }

  int query(const string& customer, const string& stock) const;

 private:
  typedef std::pair<string, int> Entry;
  typedef std::vector<Entry> EntryList;
  typedef std::map<string, EntryList> Map;
  typedef boost::shared_ptr<Map> MapPtr;
  void update(const string& customer, const EntryList& entries);
  void update(const string& message);

  static int findEntry(const EntryList& entries, const string& stock); // 用 lower_bound 在 entries 里找 stock
  static MapPtr parseData(const string& message);

  MapPtr getData() const
  {
    muduo::MutexLockGuard lock(mutex_);
    return data_;
  }

  mutable muduo::MutexLock mutex_;
  MapPtr data_; // 指向当前数据快照
};

int CustomerData::query(const string& customer, const string& stock) const
{
  MapPtr data = getData(); // data 一旦拿到，就不再需要锁了。; 取数据的时候只有 getData()内部有锁，多线程并发读的性能很好。
                           // 内部加锁，返回 shared_ptr 副本
  Map::const_iterator entries = data->find(customer);
  if (entries != data->end())
    return findEntry(entries->second, stock);
  else
    return -1;
}

void CustomerData::update(const string& customer, const EntryList& entries) // 每次收到一个customer的数据更新
{
  muduo::MutexLockGuard lock(mutex_); // update必需全程持锁
  if (!data_.unique()) // 若有其他读者
  {
    MapPtr newData(new Map(*data_)); // 拷贝旧数据
    // 在这里打印日志, 然后统计日志判断worst case发生的次数
    data_.swap(newData); // 在锁内替换
  }
  assert(data_.unique());
  (*data_)[customer] = entries;
}

void CustomerData::update(const string& message)
{
  MapPtr newData = parseData(message); // 临界区外解析
  if (newData)
  {
    muduo::MutexLockGuard lock(mutex_);
    data_.swap(newData); // O(1) 替换
  } // 旧数据析构在锁外
}

int main()
{
  CustomerData data;
}
